package com.alan.api.interceptior;

import com.alan.api.share.common.enums.ResponseCodeEnum;
import com.alan.api.share.dto.common.ResponseBase;
import com.alan.api.util.ApiSignUtils;
import com.alan.api.util.ResponseUtils;
import com.alan.api.util.TokenUtils;
import com.alibaba.fastjson.JSON;
import com.xiaoleilu.hutool.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Map;

/**
 * Created by Alan on 17-10-13
 */
@Slf4j
public class LogInterceptor implements HandlerInterceptor{
    private static final ThreadLocal<Long> startTimeThreadLocal =
            new NamedThreadLocal<Long>("ThreadLocal StartTime");
    private CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        if (log.isDebugEnabled()){
            long beginTime = System.currentTimeMillis();//1、开始时间
            startTimeThreadLocal.set(beginTime);		//线程绑定变量（该数据只有当前请求的线程可见）
            log.debug("开始计时: {}  URI: {}", new SimpleDateFormat("hh:mm:ss.SSS")
                    .format(beginTime), request.getRequestURI());
            // 打印http请求日志
            String contentType = request.getContentType();//获取请求的content-type
            Map map = null;
            if(contentType != null && contentType.contains("multipart/form-data")) {//文件上传请求 *特殊请求
                /*
                CommonsMultipartResolver 是spring框架中自带的类，
                使用multipartResolver.resolveMultipart(final HttpServletRequest request)方法可以将request转化为MultipartHttpServletRequest
                使用MultipartHttpServletRequest对象可以使用getParameter(key)获取对应属性的值
                */
                MultipartHttpServletRequest multiReq = multipartResolver.resolveMultipart(request);
                request = multiReq;//将转化后的reuqest赋值到过滤链中的参数 *重要
                map = request.getParameterMap();
            }else{//非文件上传请求
                map = request.getParameterMap();
            }
            log.debug("api请求 URI : {} parameter : {}",request.getRequestURI(),JSON.toJSONString(map));
        }
        //login check
        String uri = request.getRequestURI();
        if(uri == null || uri.equals("/error")){
            return true;
        } else {
            //check sign
            ResponseBase responseBase = ApiSignUtils.checkSign(request,response);
            if(responseBase.getCode().equals(ResponseCodeEnum.SUCCESS.getCode())){
                //check token
                if ( !uri.equals("/user/login")
                        && !uri.equals("/user/register")){
                    responseBase = TokenUtils.checkToken(request,response);
                    if(!responseBase.getCode().equals(ResponseCodeEnum.SUCCESS.getCode())){
                        ResponseUtils.renderJson(response,JSON.toJSONString(responseBase));
                        printDebugInfo(request);
                        return false;
                    }
                }
                return true;
            }else{
                ResponseUtils.renderJson(response,JSON.toJSONString(responseBase));
                printDebugInfo(request);
                return false;
            }
        }
//        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        printDebugInfo(request);
    }

    private void printDebugInfo(HttpServletRequest request) {
        // 打印JVM信息。
        if (log.isDebugEnabled()){
            // 打印http请求返回日志
            log.debug("api返回 URI : {} parameter : {}",request.getRequestURI(), JSON.toJSONString(request.getParameterMap()));
            long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量（开始时间）
            long endTime = System.currentTimeMillis(); 	//2、结束时间
            log.debug("计时结束：{}  耗时：{}  URI: {}  最大内存: {}m  已分配内存: {}m  已分配内存中的剩余空间: {}m  最大可用内存: {}m",
                    new SimpleDateFormat("hh:mm:ss.SSS").format(endTime), DateUtil.formatBetween(endTime - beginTime),
                    request.getRequestURI(), Runtime.getRuntime().maxMemory()/1024/1024, Runtime.getRuntime().totalMemory()/1024/1024, Runtime.getRuntime().freeMemory()/1024/1024,
                    (Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory())/1024/1024);
            //删除线程变量中的数据，防止内存泄漏
            startTimeThreadLocal.remove();
        }
    }


}
